
using System;
using System.Collections.Generic;
using UnityEngine;

namespace XFGameFramework.MissionSystem
{
    /// <summary>
    /// 任务系统业务逻辑
    /// </summary>
    public class MissionManager
    {

        #region 字段
        /// <summary>
        /// 缓存string的hash值
        /// </summary>
        private static Dictionary<string, int> string_to_hash = new Dictionary<string, int>();
        /// <summary>
        /// 记录hash对应的string(仅内部使用)
        /// </summary>
        private static Dictionary<int, string> hash_to_string = new Dictionary<int, string>();

        /// <summary>
        /// 所有的任务
        /// </summary>
        private static Dictionary<int, Dictionary<int, MissionBase>> missions = new Dictionary<int, Dictionary<int, MissionBase>>();

        /// <summary>
        /// 所有的参数
        /// </summary>
        private static Dictionary<int, Dictionary<int, MissionParameter>> parameters = new Dictionary<int, Dictionary<int, MissionParameter>>();


        /// <summary>
        /// 参数对应的任务
        /// </summary>
        private static Dictionary<int, Dictionary<int, List<MissionBase>>> parameter_missions = new Dictionary<int, Dictionary<int, List<MissionBase>>>();
         
        #endregion

        #region Config

        private static Dictionary<int, MissionsConfig> configs = new Dictionary<int, MissionsConfig>();

        /// <summary>
        /// 添加任务配表
        /// </summary>
        /// <param name="missionConfig">任务配置</param>
        /// <exception cref="Exception">ID重复</exception>
        public static void AddConfig(MissionsConfig missionConfig)
        {
            int config_name = StringToHash(missionConfig.name);

            if (configs.ContainsKey(config_name))
                throw new Exception(string.Format("任务配置名称:{0}重复 或 重复添加配置!", missionConfig.name));


            // 初始化参数 
            InitParamter(missionConfig);

            // 初始化任务
            InitMissions(missionConfig);

            // 初始化参数对应的任务
            InitParamterMissions(config_name);

            configs.Add(config_name, missionConfig);
        }

        private static void InitParamter(MissionsConfig missionConfig)
        {

            int config_name = StringToHash(missionConfig.name);

            // 初始化参数

            if (!parameters.ContainsKey(config_name))
                parameters.Add(config_name, new Dictionary<int, MissionParameter>());

            Dictionary<int, MissionParameter> param = parameters[config_name];

            param.Clear();

            foreach (var p in missionConfig.param)
            {
                int name = StringToHash(p.name);

                if (param.ContainsKey(name))
                    throw new Exception(string.Format("参数名称:{0}重复,请调整后重试!", p.name));
                p.Reset();
                param.Add(name, p);
            }
        }

        private static void InitMissions(MissionsConfig missionConfig)
        {
            int config_name = StringToHash(missionConfig.name);

            if (!missions.ContainsKey(config_name))
                missions.Add(config_name, new Dictionary<int, MissionBase>());

            Dictionary<int, MissionBase> m = missions[config_name];

            m.Clear();

            foreach (var config in missionConfig.missions)
            {
                // 如果配置为空 直接跳过
                if (config == null) continue;

                if (m.ContainsKey(config.id))
                    throw new Exception(string.Format("任务 配置 :{0} ID:{1}重复,请调整后重试!", missionConfig.name, config.id));

                MissionBase mission = null;

                Type t = AssemblyTools.GetType(config.mission_type_class_fullname);

                if (t != null) { 
                    mission = Activator.CreateInstance(t) as MissionBase;
                }


                if (mission == null)
                    mission = new MissionBase();

                mission.config_name = config_name;
                mission.MissionConfig = config;
                m.Add(mission.MissionConfig.id, mission);
                mission.Init(); // 初始化
            }
        }

        private static void InitParamterMissions(int config_name_hash)
        {

            if (!parameters.ContainsKey(config_name_hash)) return;

            if (!missions.ContainsKey(config_name_hash)) return;

            if (!parameter_missions.ContainsKey(config_name_hash))
                parameter_missions.Add(config_name_hash, new Dictionary<int, List<MissionBase>>());

            Dictionary<int, List<MissionBase>> p_missions = parameter_missions[config_name_hash];

            p_missions.Clear();

            // 遍历所有参数


            foreach (int param_name in parameters[config_name_hash].Keys)
            {
                MissionParameter p = parameters[config_name_hash][param_name];
                if (p == null) continue;

                if (!p_missions.ContainsKey(param_name))
                    p_missions.Add(param_name, new List<MissionBase>());

                List<MissionBase> ms = p_missions[param_name];
                ms.Clear();

                // 遍历所有任务
                foreach (var m in missions[config_name_hash].Values)
                {
                    foreach (var condition in m.MissionConfig.conditions)
                    {
                        if(string.IsNullOrEmpty(condition.param_name)) 
                            continue;

                        if (condition.param_name == p.name)
                        {
                            ms.Add(m);
                            //Debug.LogFormat("参数:{0} 对应的任务:{1}",p.name,m.MissionConfig.mission_name);
                            break;
                        }
                    }
                } 
            }

        }

        /// <summary>
        /// 查询配表
        /// </summary>
        /// <param name="name">配表名称</param>
        /// <returns></returns>
        public static MissionsConfig GetConfig(string name)
        {
            return GetConfig(StringToHash(name));
        }

        /// <summary>
        /// 查询配表
        /// </summary>
        /// <param name="name_hash">配表名称的hash值</param>
        /// <returns></returns>
        public static MissionsConfig GetConfig(int name_hash)
        {
            if (configs.ContainsKey(name_hash))
                return configs[name_hash];

            return null;
        }

        /// <summary>
        /// 移除配表
        /// </summary>
        /// <param name="name">配表名称</param>
        public static void RemoveConfig(string name)
        {
            RemoveConfig(StringToHash(name));
        }

        /// <summary>
        /// 移除配表
        /// </summary>
        /// <param name="name_hash">配表名称hash</param>
        public static void RemoveConfig(int name_hash)
        {
            if (configs.ContainsKey(name_hash))
                configs.Remove(name_hash);
             
            // 移除参数
            if (parameters.ContainsKey(name_hash))
                parameters[name_hash].Clear();

            // 移除任务
            if (missions.ContainsKey(name_hash))
                missions[name_hash].Clear();
              
            // 移除参数和任务的映射
            if(parameter_missions.ContainsKey(name_hash))
                parameter_missions[name_hash].Clear();

        }

        #endregion

        #region 方法

        /// <summary>
        /// 查询任务
        /// </summary>
        /// <param name="config_name">任务所在配置文件名称</param>
        /// <param name="id">任务id</param>
        /// <returns></returns>
        public static MissionBase GetMission(string config_name, int id) { 
            return GetMission(StringToHash(config_name), id);
        }

        /// <summary>
        /// 查询任务
        /// </summary>
        /// <param name="config_name_hash">任务配表名称hash</param>
        /// <param name="id">任务id</param>
        /// <returns></returns>
        public static MissionBase GetMission(int config_name_hash, int id)
        {
            if (!missions.ContainsKey(config_name_hash))
                return null;

            if (!missions[config_name_hash].ContainsKey(id))
                return null;

            return missions[config_name_hash][id];
        }

        /// <summary>
        /// 获取某一个配置的所有任务
        /// </summary>
        /// <param name="config_name"></param>
        /// <returns></returns>
        public static List<MissionBase> GetAllMissions(string config_name)
        { 
            return GetAllMissions(StringToHash(config_name));
        }

        /// <summary>
        /// 获取某一个配置的所有任务
        /// </summary>
        /// <param name="config_name_hash"></param>
        /// <returns></returns>
        public static List<MissionBase> GetAllMissions(int config_name_hash)
        {

            List<MissionBase> missions = new List<MissionBase>(); 
            GetAllMissionsNonAlloc(config_name_hash, missions); 
            return missions;
        }

        public static void GetAllMissionsNonAlloc(string config_name, List<MissionBase> results) 
        {
            GetAllMissionsNonAlloc(StringToHash(config_name),results);
        }

        public static void GetAllMissionsNonAlloc(int config_name_hash,List<MissionBase> results)
        {

            if (results == null)
                throw new Exception("results is null!");

            results.Clear();
             
            if (missions.ContainsKey(config_name_hash))
            {
                foreach (var mission in missions[config_name_hash].Values)
                {
                    results.Add(mission);
                }
            } 
        }


        /// <summary>
        /// 获取某一个配置的所有参数
        /// </summary>
        /// <param name="config_name">任务所在配置文件名称</param>
        /// <returns></returns>
        public static List<MissionParameter> GetAllParameters(string config_name) 
        { 
            return GetAllParameters(StringToHash(config_name));
        }

        /// <summary>
        /// 获取某一个配置的所有参数
        /// </summary>
        /// <param name="config_name_hash">任务所在配置文件名称hash</param>
        /// <returns></returns>
        public static List<MissionParameter> GetAllParameters(int config_name_hash)
        {

            List<MissionParameter> parameters = new List<MissionParameter>();

            GetAllParametersNonAlloc(config_name_hash, parameters); 

            return parameters; 
        }


        public static void GetAllParametersNonAlloc(string config_name, List<MissionParameter> results) 
        {
            GetAllParametersNonAlloc(StringToHash(config_name), results);
        }

        public static void GetAllParametersNonAlloc(int config_name_hash,List<MissionParameter> results)
        {
            if (results == null)
                throw new Exception("results is null!");

            results.Clear();

            if (parameters.ContainsKey(config_name_hash))
            {
                foreach (var p in parameters[config_name_hash].Values)
                {
                    results.Add(p);
                }
            } 
        }

        /// <summary>
        /// 重置所有参数和任务的状态
        /// </summary>
        public static void Reset()
        {
            foreach (var item in configs.Keys)
            {
                Reset(item);
            }
        }

        /// <summary>
        /// 重置某一个配置的所有参数和任务的状态
        /// </summary>
        /// <param name="config_name">任务所在配置文件名称</param>
        public static void Reset(string config_name) 
        {
            Reset(StringToHash(config_name));
        }

        /// <summary>
        /// 重置某一个配置的所有参数和任务的状态
        /// </summary>
        /// <param name="config_name_hash">任务所在配置文件名称hash</param>
        public static void Reset(int config_name_hash) 
        {
            if (parameters.ContainsKey(config_name_hash)) 
            {
                foreach (var p in parameters[config_name_hash].Values)
                {
                    p.Reset();
                }
            }

            if (missions.ContainsKey(config_name_hash)) 
            {
                foreach (var m in missions[config_name_hash].Values)
                {
                    m.Reset();
                }
            } 
        }

        /// <summary>
        /// 把字符串转成hash值
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static int StringToHash(string str)
        {
            if (string_to_hash.ContainsKey(str))
                return string_to_hash[str];

            int hash = Animator.StringToHash(str);

            string_to_hash.Add(str, hash);

            if (!hash_to_string.ContainsKey(hash))
                hash_to_string.Add(hash, str);

            return string_to_hash[str];
        }

        private static string HashToString(int str)
        {
            if (hash_to_string.ContainsKey(str))
                return hash_to_string[str];

            return string.Empty;
        }

        internal static List<MissionBase> GetParamRefMission(int config_name, int param_name)
        { 
            if (!parameter_missions.ContainsKey(config_name)) return null; 
            if (!parameter_missions[config_name].ContainsKey(param_name)) return null; 
            return parameter_missions[config_name][param_name];
        }

        #endregion

        #region 参数

        internal static MissionParameter GetMissionParam(int config_name_hash, int param_name_hash)
        {
            if (!parameters.ContainsKey(config_name_hash))
            {
                //Debug.LogWarningFormat("未发现 配置:{0} 参数:{1}", HashToString(config_name), HashToString(name));
                return null;
            }

            if (!parameters[config_name_hash].ContainsKey(param_name_hash))
            {
                //Debug.LogWarningFormat("未发现 配置:{0} 参数:{1}", HashToString(config_name), HashToString(name));
                return null;
            }
             
            return parameters[config_name_hash][param_name_hash];
        }

        /// <summary>
        /// 修改bool类型的参数值
        /// </summary>
        /// <param name="config_name">任务所在配置文件名称</param>
        /// <param name="param_name">参数名称</param>
        /// <param name="value">值</param>
        public static void SetBool(string config_name, string param_name, bool value)
        {
            SetBool(StringToHash(config_name), StringToHash(param_name), value);
        }

        /// <summary>
        /// 修改int类型的参数值
        /// </summary>
        /// <param name="config_name">任务所在配置文件名称</param>
        /// <param name="param_name">参数名称</param>
        /// <param name="value">值</param>
        public static void SetInt(string config_name, string param_name, int value)
        {
            SetInt(StringToHash(config_name), StringToHash(param_name), value );
        }

        /// <summary>
        /// 修改float类型的参数值
        /// </summary>
        /// <param name="config_name">任务所在配置文件名称</param>
        /// <param name="param_name">参数名称</param>
        /// <param name="value">值</param>
        public static void SetFloat(string config_name, string param_name, float value)
        {
            SetFloat(StringToHash(config_name), StringToHash(param_name), value);
        }

        /// <summary>
        /// 修改bool类型的参数值
        /// </summary>
        /// <param name="config_name_hash">任务所在配置文件名称hash</param>
        /// <param name="param_name_hash">参数名称hash</param>
        /// <param name="value">值</param>
        public static void SetBool(int config_name_hash, int param_name_hash, bool value)
        {
            SetParmater(config_name_hash, param_name_hash, value ? 1 : 0, MissionParamType.Bool);
        }

        /// <summary>
        /// 修改int类型的参数值
        /// </summary>
        /// <param name="config_name_hash">任务所在配置文件名称hash</param>
        /// <param name="param_name_hash">参数名称hash</param>
        /// <param name="value">值</param>
        public static void SetInt(int config_name_hash, int param_name_hash, int value)
        {
            SetParmater(config_name_hash, param_name_hash, value, MissionParamType.Int);
        }

        /// <summary>
        /// 修改float类型的参数值
        /// </summary>
        /// <param name="config_name_hash">任务所在配置文件名称hash</param>
        /// <param name="param_name_hash">参数名称hash</param>
        /// <param name="value">值</param>
        public static void SetFloat(int config_name_hash, int param_name_hash, float value)
        {
            SetParmater(config_name_hash, param_name_hash, value, MissionParamType.Float);
        }
         
        private static void SetParmater(int config_name_hash, int param_name_hash, float value, MissionParamType type)
        {
            if (!parameters.ContainsKey(config_name_hash))
            {
                Debug.LogWarningFormat("未发现 配置:{0} 参数:{1}", HashToString(config_name_hash), HashToString(param_name_hash));
                return;
            }

            if (!parameters[config_name_hash].ContainsKey(param_name_hash))
            {
                Debug.LogWarningFormat("未发现 配置:{0} 参数:{1}", HashToString(config_name_hash), HashToString(param_name_hash));
                return;
            }

            // 判断类型
            if (parameters[config_name_hash][param_name_hash].type != type)
            {
                Debug.LogWarningFormat("配置:{0} 参数:{1} 类型: {2} 不匹配!", HashToString(config_name_hash), HashToString(param_name_hash), parameters[config_name_hash][param_name_hash].type);
                return;
            }

            // 判断是否有任务在执行中

            if (parameters[config_name_hash][param_name_hash].only_can_set_in_progress)
            { 
                if (!ParamMissionIsProgress(config_name_hash, param_name_hash))
                    return;
            }

            if (parameters[config_name_hash][param_name_hash].only_can_set_larger)
            {
                if(value > parameters[config_name_hash][param_name_hash].Value)
                    parameters[config_name_hash][param_name_hash].Value = value;
            }
            else 
            {
                parameters[config_name_hash][param_name_hash].Value = value;
            }

        }

        private static bool ParamMissionIsProgress(int config_name_hash,int param_name_hash)
        {

            List<MissionBase> missions = GetParamRefMission(config_name_hash, param_name_hash);
             
            foreach (var item in missions)
            {
                if (item.State == MissionState.InProgress)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// 查询bool类型参数的值
        /// </summary>
        /// <param name="config_name">任务所在配置文件名称</param>
        /// <param name="param_name">参数名称</param>
        /// <returns></returns>
        public static bool GetBool(string config_name, string param_name)
        {
            return GetBool(StringToHash(config_name), StringToHash(param_name));
        }

        /// <summary>
        /// 查询int类型参数的值
        /// </summary>
        /// <param name="config_name">任务所在配置文件名称</param>
        /// <param name="param_name">参数名称</param>
        /// <returns></returns>
        public static int GetInt(string config_name, string param_name)
        {
            return GetInt(StringToHash(config_name), StringToHash(param_name));
        }

        /// <summary>
        /// 查询float类型参数的值
        /// </summary>
        /// <param name="config_name">任务所在配置文件名称</param>
        /// <param name="param_name">参数名称</param>
        /// <returns></returns>
        public static float GetFloat(string config_name, string param_name)
        {
            return GetFloat(StringToHash(config_name), StringToHash(param_name));
        }

        /// <summary>
        /// 查询bool类型参数的值
        /// </summary>
        /// <param name="config_name_hash">任务配表名称hash</param>
        /// <param name="param_name_hash">参数名称hash</param>
        /// <returns></returns>
        public static bool GetBool(int config_name_hash, int param_name_hash)
        {
            if (!parameters.ContainsKey(config_name_hash))
                return false;


            if (!parameters[config_name_hash].ContainsKey(param_name_hash))
                return false;

            // 判断类型
            if (parameters[config_name_hash][param_name_hash].type != MissionParamType.Bool)
                return false;

            return Mathf.RoundToInt(parameters[config_name_hash][param_name_hash].Value) == 1;
        }

        /// <summary>
        /// 查询int类型参数的值
        /// </summary>
        /// <param name="config_name_hash">任务所在配置文件名称hash</param>
        /// <param name="param_name_hash">参数名称hash</param>
        /// <returns></returns>
        public static int GetInt(int config_name_hash, int param_name_hash)
        {
            if (!parameters.ContainsKey(config_name_hash))
                return 0;


            if (!parameters[config_name_hash].ContainsKey(param_name_hash))
                return 0;

            // 判断类型
            if (parameters[config_name_hash][param_name_hash].type != MissionParamType.Int)
                return 0;

            return Mathf.RoundToInt(parameters[config_name_hash][param_name_hash].Value);
        }

        /// <summary>
        /// 查询float类型参数的值
        /// </summary>
        /// <param name="config_name_hash">任务所在配置文件名称hash</param>
        /// <param name="param_name_hash">参数名称hash</param>
        /// <returns></returns>
        public static float GetFloat(int config_name_hash, int param_name_hash)
        {
            if (!parameters.ContainsKey(config_name_hash))
                return 0;


            if (!parameters[config_name_hash].ContainsKey(param_name_hash))
                return 0;

            // 判断类型
            if (parameters[config_name_hash][param_name_hash].type != MissionParamType.Float)
                return 0;

            return parameters[config_name_hash][param_name_hash].Value;
        }

        /// <summary>
        /// 给int类型的参数增加一定的值
        /// </summary>
        /// <param name="config_name_hash">任务所在配置文件名称hash</param>
        /// <param name="param_name_hash">参数名称hash</param>
        /// <param name="value">增加的数值</param>
        public static void AddInt(int config_name_hash, int param_name_hash, int value) 
        {
            int v = GetInt(config_name_hash, param_name_hash) + value;
            SetInt(config_name_hash, param_name_hash, v);
        }

        /// <summary>
        /// 给float类型的参数增加一定的值
        /// </summary>
        /// <param name="config_name_hash">任务所在配置文件名称hash</param>
        /// <param name="param_name_hash">参数名称hash</param>
        /// <param name="value">增加的数值</param>
        public static void AddFloat(int config_name_hash, int param_name_hash, float value) 
        {
            float v = GetFloat(config_name_hash, param_name_hash) + value;
            SetFloat(config_name_hash, param_name_hash, v);
        }

        /// <summary>
        /// 给int类型的参数增加一定的值
        /// </summary>
        /// <param name="config_name">任务所在配置文件名称</param>
        /// <param name="param_name">参数名称</param>
        /// <param name="value">增加的数值</param>
        public static void AddInt(string config_name, string param_name, int value) 
        {
            AddInt(StringToHash(config_name),StringToHash(param_name),value);
        }

        /// <summary>
        /// 给float类型的参数增加一定的值
        /// </summary>
        /// <param name="config_name">任务所在配置文件名称</param>
        /// <param name="param_name">参数名称</param>
        /// <param name="value">增加的数值</param>
        public static void AddFloat(string config_name, string param_name, float value)
        {
            AddFloat(StringToHash(config_name), StringToHash(param_name), value);
        }

        #endregion

    }

}